/**
 * monitor_plugin.c - 文件操作监控插件
 * 
 * 此插件演示如何监控和记录文件操作
 */

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <time.h>
#include "../../include/hook_framework.h"

#define LOG_FILE "file_monitor.log"

/* 是否启用监控 */
static int g_monitor_enabled = 1;

/* 日志文件 */
static FILE* g_log_file = NULL;

/**
 * 获取当前时间字符串
 */
static void get_time_string(char* buffer, size_t size) {
    time_t now = time(NULL);
    struct tm* tm_info = localtime(&now);
    strftime(buffer, size, "%Y-%m-%d %H:%M:%S", tm_info);
}

/**
 * 记录操作到日志文件
 */
static void log_operation(const char* operation, const char* path, int result) {
    if (!g_monitor_enabled || !g_log_file) return;
    
    char time_str[32];
    get_time_string(time_str, sizeof(time_str));
    
    fprintf(g_log_file, "[%s] %s: %s (结果=%d)\n", 
            time_str, operation, path ? path : "未知", result);
    fflush(g_log_file);
}

/* 获取原始函数指针 */
typedef int (*open_func_t)(const char *pathname, int flags, ...);
typedef int (*close_func_t)(int fd);
typedef ssize_t (*read_func_t)(int fd, void *buf, size_t count);
typedef ssize_t (*write_func_t)(int fd, const void *buf, size_t count);
typedef int (*unlink_func_t)(const char *pathname);
typedef int (*rename_func_t)(const char *oldpath, const char *newpath);

/**
 * open函数的拦截
 */
int open(const char *pathname, int flags, ...) {
    static open_func_t original_open = NULL;
    
    /* 初始化原始函数指针 */
    if (!original_open) {
        original_open = (open_func_t)dlsym(RTLD_NEXT, "open");
        if (!original_open) {
            fprintf(stderr, "无法获取原始open函数: %s\n", dlerror());
            exit(1);
        }
    }
    
    /* 获取mode参数（如果有） */
    mode_t mode = 0;
    if (flags & O_CREAT) {
        va_list args;
        va_start(args, flags);
        mode = va_arg(args, mode_t);
        va_end(args);
    }
    
    /* 调用原始函数 */
    int result;
    if (flags & O_CREAT) {
        result = original_open(pathname, flags, mode);
    } else {
        result = original_open(pathname, flags);
    }
    
    /* 记录操作 */
    const char* op_type = "打开";
    if (flags & O_CREAT) op_type = "创建";
    if (flags & O_TRUNC) op_type = "截断";
    if (flags & O_APPEND) op_type = "追加";
    
    char operation[64];
    snprintf(operation, sizeof(operation), "%s文件", op_type);
    log_operation(operation, pathname, result);
    
    return result;
}

/**
 * close函数的拦截
 */
int close(int fd) {
    static close_func_t original_close = NULL;
    
    /* 初始化原始函数指针 */
    if (!original_close) {
        original_close = (close_func_t)dlsym(RTLD_NEXT, "close");
        if (!original_close) {
            fprintf(stderr, "无法获取原始close函数: %s\n", dlerror());
            exit(1);
        }
    }
    
    /* 获取文件路径 */
    char fd_path[256] = {0};
    snprintf(fd_path, sizeof(fd_path), "/proc/self/fd/%d", fd);
    
    char file_path[256] = {0};
    readlink(fd_path, file_path, sizeof(file_path) - 1);
    
    /* 调用原始函数 */
    int result = original_close(fd);
    
    /* 记录操作 */
    log_operation("关闭文件", file_path[0] ? file_path : NULL, result);
    
    return result;
}

/**
 * read函数的拦截
 */
ssize_t read(int fd, void *buf, size_t count) {
    static read_func_t original_read = NULL;
    
    /* 初始化原始函数指针 */
    if (!original_read) {
        original_read = (read_func_t)dlsym(RTLD_NEXT, "read");
        if (!original_read) {
            fprintf(stderr, "无法获取原始read函数: %s\n", dlerror());
            exit(1);
        }
    }
    
    /* 获取文件路径 */
    char fd_path[256] = {0};
    snprintf(fd_path, sizeof(fd_path), "/proc/self/fd/%d", fd);
    
    char file_path[256] = {0};
    readlink(fd_path, file_path, sizeof(file_path) - 1);
    
    /* 调用原始函数 */
    ssize_t result = original_read(fd, buf, count);
    
    /* 记录操作 */
    if (file_path[0]) {  // 只记录文件操作，忽略管道、套接字等
        char operation[64];
        snprintf(operation, sizeof(operation), "读取文件(%zu字节)", count);
        log_operation(operation, file_path, (int)result);
    }
    
    return result;
}

/**
 * write函数的拦截
 */
ssize_t write(int fd, const void *buf, size_t count) {
    static write_func_t original_write = NULL;
    
    /* 初始化原始函数指针 */
    if (!original_write) {
        original_write = (write_func_t)dlsym(RTLD_NEXT, "write");
        if (!original_write) {
            fprintf(stderr, "无法获取原始write函数: %s\n", dlerror());
            exit(1);
        }
    }
    
    /* 获取文件路径 */
    char fd_path[256] = {0};
    snprintf(fd_path, sizeof(fd_path), "/proc/self/fd/%d", fd);
    
    char file_path[256] = {0};
    readlink(fd_path, file_path, sizeof(file_path) - 1);
    
    /* 调用原始函数 */
    ssize_t result = original_write(fd, buf, count);
    
    /* 记录操作 */
    if (file_path[0] && fd > 2) {  // 忽略标准输入、输出和错误
        char operation[64];
        snprintf(operation, sizeof(operation), "写入文件(%zu字节)", count);
        log_operation(operation, file_path, (int)result);
    }
    
    return result;
}

/**
 * unlink函数的拦截
 */
int unlink(const char *pathname) {
    static unlink_func_t original_unlink = NULL;
    
    /* 初始化原始函数指针 */
    if (!original_unlink) {
        original_unlink = (unlink_func_t)dlsym(RTLD_NEXT, "unlink");
        if (!original_unlink) {
            fprintf(stderr, "无法获取原始unlink函数: %s\n", dlerror());
            exit(1);
        }
    }
    
    /* 调用原始函数 */
    int result = original_unlink(pathname);
    
    /* 记录操作 */
    log_operation("删除文件", pathname, result);
    
    return result;
}

/**
 * rename函数的拦截
 */
int rename(const char *oldpath, const char *newpath) {
    static rename_func_t original_rename = NULL;
    
    /* 初始化原始函数指针 */
    if (!original_rename) {
        original_rename = (rename_func_t)dlsym(RTLD_NEXT, "rename");
        if (!original_rename) {
            fprintf(stderr, "无法获取原始rename函数: %s\n", dlerror());
            exit(1);
        }
    }
    
    /* 调用原始函数 */
    int result = original_rename(oldpath, newpath);
    
    /* 记录操作 */
    char operation[256];
    snprintf(operation, sizeof(operation), "重命名文件: %s -> %s", oldpath, newpath);
    log_operation(operation, "", result);
    
    return result;
}

/**
 * 加载插件
 */
int plugin_init(void) {
    fprintf(stderr, "[监控插件] 文件操作监控插件正在初始化\n");
    
    /* 打开日志文件 */
    g_log_file = fopen(LOG_FILE, "a");
    if (!g_log_file) {
        fprintf(stderr, "[监控插件] 无法打开日志文件: %s\n", LOG_FILE);
        g_monitor_enabled = 0;
        return -1;
    }
    
    /* 写入初始化信息 */
    char time_str[32];
    get_time_string(time_str, sizeof(time_str));
    fprintf(g_log_file, "\n[%s] === 文件监控会话开始 ===\n", time_str);
    fflush(g_log_file);
    
    fprintf(stderr, "[监控插件] 文件操作监控插件已初始化，日志文件: %s\n", LOG_FILE);
    return 0;
}

/**
 * 卸载插件
 */
void plugin_cleanup(void) {
    fprintf(stderr, "[监控插件] 文件操作监控插件正在关闭\n");
    
    if (g_log_file) {
        /* 写入关闭信息 */
        char time_str[32];
        get_time_string(time_str, sizeof(time_str));
        fprintf(g_log_file, "[%s] === 文件监控会话结束 ===\n\n", time_str);
        fclose(g_log_file);
        g_log_file = NULL;
    }
} 